///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////


#include <EAStdC/EAHashCRC.h>


namespace EA
{
namespace StdC
{



///////////////////////////////////////////////////////////////////////////////
// CRC16 
///////////////////////////////////////////////////////////////////////////////

EASTDC_API uint16_t crc16Table[256] =
{
	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 
	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 
	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 
	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 
	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 
	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 
	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 
	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 
	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 
	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 
	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 
	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 
	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 
	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 
	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 
	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 
	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 
	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 
	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 
	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 
	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 
	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 
	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 
	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 
	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 
	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 
	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 
	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 
	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 
	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 
	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 
	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 
};


EASTDC_API uint16_t CRC16(const void* pData, size_t nLength, uint16_t nInitialValue, bool bFinalize)
{
	const uint8_t*       pData8    = (const uint8_t*)pData;
	const uint8_t* const pData8End = pData8 + nLength;
	unsigned             tempValue = nInitialValue;

	while(pData8 < pData8End)
		tempValue = ((tempValue >> 8) ^ crc16Table[(tempValue ^ *pData8++) & 0xff]);

	if(bFinalize)
		tempValue = ~tempValue;

	return (uint16_t)tempValue;
}




///////////////////////////////////////////////////////////////////////////////
// CRC24 
///////////////////////////////////////////////////////////////////////////////

EASTDC_API uint32_t crc24Table[256] = 
{
	0x00000000, 0x00d6a776, 0x00f64557, 0x0020e221, 0x00b78115, 0x00612663, 0x0041c442, 0x00976334, 
	0x00340991, 0x00e2aee7, 0x00c24cc6, 0x0014ebb0, 0x00838884, 0x00552ff2, 0x0075cdd3, 0x00a36aa5, 
	0x00681322, 0x00beb454, 0x009e5675, 0x0048f103, 0x00df9237, 0x00093541, 0x0029d760, 0x00ff7016, 
	0x005c1ab3, 0x008abdc5, 0x00aa5fe4, 0x007cf892, 0x00eb9ba6, 0x003d3cd0, 0x001ddef1, 0x00cb7987, 
	0x00d02644, 0x00068132, 0x00266313, 0x00f0c465, 0x0067a751, 0x00b10027, 0x0091e206, 0x00474570, 
	0x00e42fd5, 0x003288a3, 0x00126a82, 0x00c4cdf4, 0x0053aec0, 0x008509b6, 0x00a5eb97, 0x00734ce1, 
	0x00b83566, 0x006e9210, 0x004e7031, 0x0098d747, 0x000fb473, 0x00d91305, 0x00f9f124, 0x002f5652, 
	0x008c3cf7, 0x005a9b81, 0x007a79a0, 0x00acded6, 0x003bbde2, 0x00ed1a94, 0x00cdf8b5, 0x001b5fc3, 
	0x00fb4733, 0x002de045, 0x000d0264, 0x00dba512, 0x004cc626, 0x009a6150, 0x00ba8371, 0x006c2407, 
	0x00cf4ea2, 0x0019e9d4, 0x00390bf5, 0x00efac83, 0x0078cfb7, 0x00ae68c1, 0x008e8ae0, 0x00582d96, 
	0x00935411, 0x0045f367, 0x00651146, 0x00b3b630, 0x0024d504, 0x00f27272, 0x00d29053, 0x00043725, 
	0x00a75d80, 0x0071faf6, 0x005118d7, 0x0087bfa1, 0x0010dc95, 0x00c67be3, 0x00e699c2, 0x00303eb4, 
	0x002b6177, 0x00fdc601, 0x00dd2420, 0x000b8356, 0x009ce062, 0x004a4714, 0x006aa535, 0x00bc0243, 
	0x001f68e6, 0x00c9cf90, 0x00e92db1, 0x003f8ac7, 0x00a8e9f3, 0x007e4e85, 0x005eaca4, 0x00880bd2, 
	0x00437255, 0x0095d523, 0x00b53702, 0x00639074, 0x00f4f340, 0x00225436, 0x0002b617, 0x00d41161, 
	0x00777bc4, 0x00a1dcb2, 0x00813e93, 0x005799e5, 0x00c0fad1, 0x00165da7, 0x0036bf86, 0x00e018f0, 
	0x00ad85dd, 0x007b22ab, 0x005bc08a, 0x008d67fc, 0x001a04c8, 0x00cca3be, 0x00ec419f, 0x003ae6e9, 
	0x00998c4c, 0x004f2b3a, 0x006fc91b, 0x00b96e6d, 0x002e0d59, 0x00f8aa2f, 0x00d8480e, 0x000eef78, 
	0x00c596ff, 0x00133189, 0x0033d3a8, 0x00e574de, 0x007217ea, 0x00a4b09c, 0x008452bd, 0x0052f5cb, 
	0x00f19f6e, 0x00273818, 0x0007da39, 0x00d17d4f, 0x00461e7b, 0x0090b90d, 0x00b05b2c, 0x0066fc5a, 
	0x007da399, 0x00ab04ef, 0x008be6ce, 0x005d41b8, 0x00ca228c, 0x001c85fa, 0x003c67db, 0x00eac0ad, 
	0x0049aa08, 0x009f0d7e, 0x00bfef5f, 0x00694829, 0x00fe2b1d, 0x00288c6b, 0x00086e4a, 0x00dec93c, 
	0x0015b0bb, 0x00c317cd, 0x00e3f5ec, 0x0035529a, 0x00a231ae, 0x007496d8, 0x005474f9, 0x0082d38f, 
	0x0021b92a, 0x00f71e5c, 0x00d7fc7d, 0x00015b0b, 0x0096383f, 0x00409f49, 0x00607d68, 0x00b6da1e, 
	0x0056c2ee, 0x00806598, 0x00a087b9, 0x007620cf, 0x00e143fb, 0x0037e48d, 0x001706ac, 0x00c1a1da, 
	0x0062cb7f, 0x00b46c09, 0x00948e28, 0x0042295e, 0x00d54a6a, 0x0003ed1c, 0x00230f3d, 0x00f5a84b, 
	0x003ed1cc, 0x00e876ba, 0x00c8949b, 0x001e33ed, 0x008950d9, 0x005ff7af, 0x007f158e, 0x00a9b2f8, 
	0x000ad85d, 0x00dc7f2b, 0x00fc9d0a, 0x002a3a7c, 0x00bd5948, 0x006bfe3e, 0x004b1c1f, 0x009dbb69, 
	0x0086e4aa, 0x005043dc, 0x0070a1fd, 0x00a6068b, 0x003165bf, 0x00e7c2c9, 0x00c720e8, 0x0011879e, 
	0x00b2ed3b, 0x00644a4d, 0x0044a86c, 0x00920f1a, 0x00056c2e, 0x00d3cb58, 0x00f32979, 0x00258e0f, 
	0x00eef788, 0x003850fe, 0x0018b2df, 0x00ce15a9, 0x0059769d, 0x008fd1eb, 0x00af33ca, 0x007994bc, 
	0x00dafe19, 0x000c596f, 0x002cbb4e, 0x00fa1c38, 0x006d7f0c, 0x00bbd87a, 0x009b3a5b, 0x004d9d2d 
};


EASTDC_API uint32_t CRC24(const void* pData, size_t nLength, uint32_t nInitialValue, bool bFinalize)
{
	const uint8_t*       pData8    = (const uint8_t*)pData;
	const uint8_t* const pData8End = pData8 + nLength;

	while(pData8 < pData8End)
		nInitialValue = (nInitialValue >> 8) ^ crc24Table[(nInitialValue ^ *pData8++) & 0xff];

	if(bFinalize)
	{
		nInitialValue = ~nInitialValue;
		nInitialValue &= 0x00ffffff;
	}

	return nInitialValue;
}





///////////////////////////////////////////////////////////////////////////////
// CRC32
///////////////////////////////////////////////////////////////////////////////

EASTDC_API uint32_t crc32Table[256] =
{
	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
	0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 
	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 
	0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 
	0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 
	0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 
	0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 
	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 
	0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 
	0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 
	0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 
	0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 
	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 
	0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 
	0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 
	0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 
	0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 
	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 
	0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 
	0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 
	0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 
	0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 
	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 
	0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 
	0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 
	0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 
	0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 
	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 
	0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 
	0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 
	0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 
	0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};


EASTDC_API uint32_t CRC32(const void* pData, size_t nLength, uint32_t nInitialValue, bool bFinalize)
{
	const uint8_t*       pData8    = (const uint8_t*)pData;
	const uint8_t* const pData8End = pData8 + nLength;

	while(pData8 < pData8End)
		nInitialValue = (nInitialValue << 8) ^ crc32Table[(nInitialValue >> 24) ^ *pData8++];

	if(bFinalize)
		nInitialValue = ~nInitialValue;

	return nInitialValue;
}






EASTDC_API uint32_t crc32TableReverse[256] =
{
	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 
	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 
	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 
	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 
	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 
	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 
	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 
	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 
	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 
	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 
	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 
	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 
	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 
	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 
	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 
	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 
	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 
	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 
	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 
	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 
	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 
	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 
	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 
	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 
	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 
	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 
	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 
	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 
	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 
	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 
	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 
	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};


EASTDC_API uint32_t CRC32Reverse(const void* pData, size_t nLength, uint32_t nInitialValue, bool bFinalize)
{
	const uint8_t* pData8 = (const uint8_t*)pData;

	while(nLength >= 8)
	{
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);
		nLength -= 8;
	}

	while(nLength--)
		nInitialValue = crc32TableReverse[(nInitialValue ^ *pData8++) & 0xff] ^ (nInitialValue >> 8);

	if(bFinalize)
		nInitialValue = ~nInitialValue;

	return nInitialValue;
}





EASTDC_API uint32_t CRC32Rwstdc(const void* pData, size_t nLength)
{
	unsigned result;
	const uint8_t* d = static_cast<const uint8_t*>(pData);

	if(nLength < 4)
	{
		result = *d;

		while(nLength--)
			result = ((result << 8) | *d++) ^ crc32Table[result & 0xff];

		return result;
	}

	result  = static_cast<unsigned>(*d++ << 24);
	result |= *d++ << 16;
	result |= *d++ << 8;
	result |= *d++;
	result  = ~result;

	nLength -= 4;

	for(size_t i = 0; i < nLength; i++)
		result = ((result << 8) | *d++) ^ crc32Table[result >> 24];

	return (uint32_t)~result;
}





///////////////////////////////////////////////////////////////////////////////
// CRC64 
///////////////////////////////////////////////////////////////////////////////

// We follow the same polynomial convention as the ECMA-182 tape drive standard.
EASTDC_API uint64_t crc64Table[256] =
{
	UINT64_C(0x0000000000000000), UINT64_C(0x42f0e1eba9ea3693), UINT64_C(0x85e1c3d753d46d26), UINT64_C(0xc711223cfa3e5bb5), 
	UINT64_C(0x493366450e42ecdf), UINT64_C(0x0bc387aea7a8da4c), UINT64_C(0xccd2a5925d9681f9), UINT64_C(0x8e224479f47cb76a), 
	UINT64_C(0x9266cc8a1c85d9be), UINT64_C(0xd0962d61b56fef2d), UINT64_C(0x17870f5d4f51b498), UINT64_C(0x5577eeb6e6bb820b), 
	UINT64_C(0xdb55aacf12c73561), UINT64_C(0x99a54b24bb2d03f2), UINT64_C(0x5eb4691841135847), UINT64_C(0x1c4488f3e8f96ed4), 
	UINT64_C(0x663d78ff90e185ef), UINT64_C(0x24cd9914390bb37c), UINT64_C(0xe3dcbb28c335e8c9), UINT64_C(0xa12c5ac36adfde5a), 
	UINT64_C(0x2f0e1eba9ea36930), UINT64_C(0x6dfeff5137495fa3), UINT64_C(0xaaefdd6dcd770416), UINT64_C(0xe81f3c86649d3285), 
	UINT64_C(0xf45bb4758c645c51), UINT64_C(0xb6ab559e258e6ac2), UINT64_C(0x71ba77a2dfb03177), UINT64_C(0x334a9649765a07e4), 
	UINT64_C(0xbd68d2308226b08e), UINT64_C(0xff9833db2bcc861d), UINT64_C(0x388911e7d1f2dda8), UINT64_C(0x7a79f00c7818eb3b), 
	UINT64_C(0xcc7af1ff21c30bde), UINT64_C(0x8e8a101488293d4d), UINT64_C(0x499b3228721766f8), UINT64_C(0x0b6bd3c3dbfd506b), 
	UINT64_C(0x854997ba2f81e701), UINT64_C(0xc7b97651866bd192), UINT64_C(0x00a8546d7c558a27), UINT64_C(0x4258b586d5bfbcb4), 
	UINT64_C(0x5e1c3d753d46d260), UINT64_C(0x1cecdc9e94ace4f3), UINT64_C(0xdbfdfea26e92bf46), UINT64_C(0x990d1f49c77889d5), 
	UINT64_C(0x172f5b3033043ebf), UINT64_C(0x55dfbadb9aee082c), UINT64_C(0x92ce98e760d05399), UINT64_C(0xd03e790cc93a650a), 
	UINT64_C(0xaa478900b1228e31), UINT64_C(0xe8b768eb18c8b8a2), UINT64_C(0x2fa64ad7e2f6e317), UINT64_C(0x6d56ab3c4b1cd584), 
	UINT64_C(0xe374ef45bf6062ee), UINT64_C(0xa1840eae168a547d), UINT64_C(0x66952c92ecb40fc8), UINT64_C(0x2465cd79455e395b), 
	UINT64_C(0x3821458aada7578f), UINT64_C(0x7ad1a461044d611c), UINT64_C(0xbdc0865dfe733aa9), UINT64_C(0xff3067b657990c3a), 
	UINT64_C(0x711223cfa3e5bb50), UINT64_C(0x33e2c2240a0f8dc3), UINT64_C(0xf4f3e018f031d676), UINT64_C(0xb60301f359dbe0e5), 
	UINT64_C(0xda050215ea6c212f), UINT64_C(0x98f5e3fe438617bc), UINT64_C(0x5fe4c1c2b9b84c09), UINT64_C(0x1d14202910527a9a), 
	UINT64_C(0x93366450e42ecdf0), UINT64_C(0xd1c685bb4dc4fb63), UINT64_C(0x16d7a787b7faa0d6), UINT64_C(0x5427466c1e109645), 
	UINT64_C(0x4863ce9ff6e9f891), UINT64_C(0x0a932f745f03ce02), UINT64_C(0xcd820d48a53d95b7), UINT64_C(0x8f72eca30cd7a324), 
	UINT64_C(0x0150a8daf8ab144e), UINT64_C(0x43a04931514122dd), UINT64_C(0x84b16b0dab7f7968), UINT64_C(0xc6418ae602954ffb), 
	UINT64_C(0xbc387aea7a8da4c0), UINT64_C(0xfec89b01d3679253), UINT64_C(0x39d9b93d2959c9e6), UINT64_C(0x7b2958d680b3ff75), 
	UINT64_C(0xf50b1caf74cf481f), UINT64_C(0xb7fbfd44dd257e8c), UINT64_C(0x70eadf78271b2539), UINT64_C(0x321a3e938ef113aa), 
	UINT64_C(0x2e5eb66066087d7e), UINT64_C(0x6cae578bcfe24bed), UINT64_C(0xabbf75b735dc1058), UINT64_C(0xe94f945c9c3626cb), 
	UINT64_C(0x676dd025684a91a1), UINT64_C(0x259d31cec1a0a732), UINT64_C(0xe28c13f23b9efc87), UINT64_C(0xa07cf2199274ca14), 
	UINT64_C(0x167ff3eacbaf2af1), UINT64_C(0x548f120162451c62), UINT64_C(0x939e303d987b47d7), UINT64_C(0xd16ed1d631917144), 
	UINT64_C(0x5f4c95afc5edc62e), UINT64_C(0x1dbc74446c07f0bd), UINT64_C(0xdaad56789639ab08), UINT64_C(0x985db7933fd39d9b), 
	UINT64_C(0x84193f60d72af34f), UINT64_C(0xc6e9de8b7ec0c5dc), UINT64_C(0x01f8fcb784fe9e69), UINT64_C(0x43081d5c2d14a8fa), 
	UINT64_C(0xcd2a5925d9681f90), UINT64_C(0x8fdab8ce70822903), UINT64_C(0x48cb9af28abc72b6), UINT64_C(0x0a3b7b1923564425), 
	UINT64_C(0x70428b155b4eaf1e), UINT64_C(0x32b26afef2a4998d), UINT64_C(0xf5a348c2089ac238), UINT64_C(0xb753a929a170f4ab), 
	UINT64_C(0x3971ed50550c43c1), UINT64_C(0x7b810cbbfce67552), UINT64_C(0xbc902e8706d82ee7), UINT64_C(0xfe60cf6caf321874), 
	UINT64_C(0xe224479f47cb76a0), UINT64_C(0xa0d4a674ee214033), UINT64_C(0x67c58448141f1b86), UINT64_C(0x253565a3bdf52d15), 
	UINT64_C(0xab1721da49899a7f), UINT64_C(0xe9e7c031e063acec), UINT64_C(0x2ef6e20d1a5df759), UINT64_C(0x6c0603e6b3b7c1ca), 
	UINT64_C(0xf6fae5c07d3274cd), UINT64_C(0xb40a042bd4d8425e), UINT64_C(0x731b26172ee619eb), UINT64_C(0x31ebc7fc870c2f78), 
	UINT64_C(0xbfc9838573709812), UINT64_C(0xfd39626eda9aae81), UINT64_C(0x3a28405220a4f534), UINT64_C(0x78d8a1b9894ec3a7), 
	UINT64_C(0x649c294a61b7ad73), UINT64_C(0x266cc8a1c85d9be0), UINT64_C(0xe17dea9d3263c055), UINT64_C(0xa38d0b769b89f6c6), 
	UINT64_C(0x2daf4f0f6ff541ac), UINT64_C(0x6f5faee4c61f773f), UINT64_C(0xa84e8cd83c212c8a), UINT64_C(0xeabe6d3395cb1a19), 
	UINT64_C(0x90c79d3fedd3f122), UINT64_C(0xd2377cd44439c7b1), UINT64_C(0x15265ee8be079c04), UINT64_C(0x57d6bf0317edaa97), 
	UINT64_C(0xd9f4fb7ae3911dfd), UINT64_C(0x9b041a914a7b2b6e), UINT64_C(0x5c1538adb04570db), UINT64_C(0x1ee5d94619af4648), 
	UINT64_C(0x02a151b5f156289c), UINT64_C(0x4051b05e58bc1e0f), UINT64_C(0x87409262a28245ba), UINT64_C(0xc5b073890b687329), 
	UINT64_C(0x4b9237f0ff14c443), UINT64_C(0x0962d61b56fef2d0), UINT64_C(0xce73f427acc0a965), UINT64_C(0x8c8315cc052a9ff6), 
	UINT64_C(0x3a80143f5cf17f13), UINT64_C(0x7870f5d4f51b4980), UINT64_C(0xbf61d7e80f251235), UINT64_C(0xfd913603a6cf24a6), 
	UINT64_C(0x73b3727a52b393cc), UINT64_C(0x31439391fb59a55f), UINT64_C(0xf652b1ad0167feea), UINT64_C(0xb4a25046a88dc879), 
	UINT64_C(0xa8e6d8b54074a6ad), UINT64_C(0xea16395ee99e903e), UINT64_C(0x2d071b6213a0cb8b), UINT64_C(0x6ff7fa89ba4afd18), 
	UINT64_C(0xe1d5bef04e364a72), UINT64_C(0xa3255f1be7dc7ce1), UINT64_C(0x64347d271de22754), UINT64_C(0x26c49cccb40811c7), 
	UINT64_C(0x5cbd6cc0cc10fafc), UINT64_C(0x1e4d8d2b65facc6f), UINT64_C(0xd95caf179fc497da), UINT64_C(0x9bac4efc362ea149), 
	UINT64_C(0x158e0a85c2521623), UINT64_C(0x577eeb6e6bb820b0), UINT64_C(0x906fc95291867b05), UINT64_C(0xd29f28b9386c4d96), 
	UINT64_C(0xcedba04ad0952342), UINT64_C(0x8c2b41a1797f15d1), UINT64_C(0x4b3a639d83414e64), UINT64_C(0x09ca82762aab78f7), 
	UINT64_C(0x87e8c60fded7cf9d), UINT64_C(0xc51827e4773df90e), UINT64_C(0x020905d88d03a2bb), UINT64_C(0x40f9e43324e99428), 
	UINT64_C(0x2cffe7d5975e55e2), UINT64_C(0x6e0f063e3eb46371), UINT64_C(0xa91e2402c48a38c4), UINT64_C(0xebeec5e96d600e57), 
	UINT64_C(0x65cc8190991cb93d), UINT64_C(0x273c607b30f68fae), UINT64_C(0xe02d4247cac8d41b), UINT64_C(0xa2dda3ac6322e288), 
	UINT64_C(0xbe992b5f8bdb8c5c), UINT64_C(0xfc69cab42231bacf), UINT64_C(0x3b78e888d80fe17a), UINT64_C(0x7988096371e5d7e9), 
	UINT64_C(0xf7aa4d1a85996083), UINT64_C(0xb55aacf12c735610), UINT64_C(0x724b8ecdd64d0da5), UINT64_C(0x30bb6f267fa73b36), 
	UINT64_C(0x4ac29f2a07bfd00d), UINT64_C(0x08327ec1ae55e69e), UINT64_C(0xcf235cfd546bbd2b), UINT64_C(0x8dd3bd16fd818bb8), 
	UINT64_C(0x03f1f96f09fd3cd2), UINT64_C(0x41011884a0170a41), UINT64_C(0x86103ab85a2951f4), UINT64_C(0xc4e0db53f3c36767), 
	UINT64_C(0xd8a453a01b3a09b3), UINT64_C(0x9a54b24bb2d03f20), UINT64_C(0x5d45907748ee6495), UINT64_C(0x1fb5719ce1045206), 
	UINT64_C(0x919735e51578e56c), UINT64_C(0xd367d40ebc92d3ff), UINT64_C(0x1476f63246ac884a), UINT64_C(0x568617d9ef46bed9), 
	UINT64_C(0xe085162ab69d5e3c), UINT64_C(0xa275f7c11f7768af), UINT64_C(0x6564d5fde549331a), UINT64_C(0x279434164ca30589), 
	UINT64_C(0xa9b6706fb8dfb2e3), UINT64_C(0xeb46918411358470), UINT64_C(0x2c57b3b8eb0bdfc5), UINT64_C(0x6ea7525342e1e956), 
	UINT64_C(0x72e3daa0aa188782), UINT64_C(0x30133b4b03f2b111), UINT64_C(0xf7021977f9cceaa4), UINT64_C(0xb5f2f89c5026dc37), 
	UINT64_C(0x3bd0bce5a45a6b5d), UINT64_C(0x79205d0e0db05dce), UINT64_C(0xbe317f32f78e067b), UINT64_C(0xfcc19ed95e6430e8), 
	UINT64_C(0x86b86ed5267cdbd3), UINT64_C(0xc4488f3e8f96ed40), UINT64_C(0x0359ad0275a8b6f5), UINT64_C(0x41a94ce9dc428066), 
	UINT64_C(0xcf8b0890283e370c), UINT64_C(0x8d7be97b81d4019f), UINT64_C(0x4a6acb477bea5a2a), UINT64_C(0x089a2aacd2006cb9), 
	UINT64_C(0x14dea25f3af9026d), UINT64_C(0x562e43b4931334fe), UINT64_C(0x913f6188692d6f4b), UINT64_C(0xd3cf8063c0c759d8), 
	UINT64_C(0x5dedc41a34bbeeb2), UINT64_C(0x1f1d25f19d51d821), UINT64_C(0xd80c07cd676f8394), UINT64_C(0x9afce626ce85b507)
};


EASTDC_API uint64_t CRC64(const void* pData, size_t nLength, uint64_t nInitialValue, bool bFinalize)
{
	const uint8_t*       pData8    = (const uint8_t*)pData;
	const uint8_t* const pData8End = pData8 + nLength;

	while(pData8 < pData8End)
	{
		const size_t nTableIndex = ((size_t)(nInitialValue >> 56) ^ *pData8++) & 0xff;
		nInitialValue = crc64Table[nTableIndex] ^ (nInitialValue << 8);
	}

	if(bFinalize)
		nInitialValue ^= UINT64_C(0xffffffffffffffff);

	return nInitialValue;
}




} // namespace StdC
} // namespace EA









